/**********************************************************************************************/
// dgt_BoolConverter.cpp
//
// Common Lib for Digital Studio
// Block of management of bool functions
// Main class, that represent converter of bool functions
//
// Copyright Diamant Group 2008
/**********************************************************************************************/
#include "dgt_BoolConverter.h"
#include "dgt_Utils.h"
#include "dgt_Log.h"

/**********************************************************************************************/
dgt_BoolConverter::dgt_BoolConverter( dgt_LogicTable_Ptr inTable )
{
	START( "DgtKernel", "dgt_BoolConverter::dgt_BoolConverter" );
	LOG_PARAM( inTable );

	dgt_BoolFunction_Ptr tFunc( new dgt_BoolFunction() );

	wxArrayString tVarNames = inTable->get_VarNames();
	tFunc->set_VarNames( tVarNames );

	unsigned tVarCount = tVarNames.Count();
	unsigned opcount = 0;					// Operations count

	map<unsigned, bool> tVal = inTable->get_Values();
	
	BoolElementArray tFunction;

	// AND Elements
	for( map<unsigned, bool>::const_iterator p = tVal.begin(); p != tVal.end(); p++ )
	{
		if( p->second )				// value - 1
		{
			dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );
			tElement->set_Operation( AND );
			for( unsigned i = 0; i < tVarCount; i++ )
			{
				bool bit = get_Bit( p->first, i+1 );
				tElement->AddNewOperand( i, bit );
			}
			opcount++;
			tFunction.Add( tElement);		
		}
	}

	// The general OR
	dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );
	tElement->set_Operation( OR );
	for( unsigned i = 0; i < opcount; i++ )
	{
		tElement->AddNewOperand( -( i + 1), true );
	}
	tFunction.Add( tElement );

	tFunc->set_Function( tFunction );
	tFunc->set_Kind( AND_OR );

	m_MainForm = tFunc;

	RETURN_VOID( "dgt_BoolConverter::dgt_BoolConverter" );
}

/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_MainForm( short	inAndInputs, short	inOrInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_MainForm" );
	LOG_PARAM( inAndInputs );
	LOG_PARAM( inOrInputs );

	if( ( !inAndInputs )&&( !inOrInputs ) )
	{
		RETURN( "dgt_BoolConverter::get_MainForm", m_MainForm );
		return m_MainForm;
	}

	dgt_BoolFunction_Ptr result( new dgt_BoolFunction() );
	BoolElementArray resArray;

	BoolElementArray tArray = m_MainForm->get_Function();
	unsigned CurPos = 1;	

	wxArrayInt AndIndexes;		// indexes of AND elements to be united by OR

	// Correcting AND
	for( unsigned i = 0; i < m_MainForm->get_IndexOfSecondOperation(); i++ )
	{
		dgt_BoolElement_Ptr tElement = tArray.Item( i );
		int tCount = tElement->Count();

		if( tCount < inAndInputs )
		{
			dgt_BoolElement_Ptr tEl = tElement->IncreaseInputs( inAndInputs );
			resArray.Add( tEl );
			AndIndexes.Add( CurPos );
			CurPos++;
		}
		else if( tCount > inAndInputs )
		{
			BoolElementArray tAr = tElement->ReduceInputs( inAndInputs );
			BoolElementArray tMerged = MergeElements( tAr, inAndInputs, false );

			unsigned StartPos;

			// specify, if second level of elements present
			bool isSecLevel;
			if( get_FirstLevelCount( tMerged ) < tMerged.Count() )
				isSecLevel = true;
			else
				isSecLevel = false;

			// Copying elements of less level
			for( unsigned i = 0; i < get_FirstLevelCount( tMerged ); i++ )
			{
				if( !i )
					StartPos = CurPos;
				resArray.Add( tMerged.Item( i ) );

				if( !isSecLevel )
					AndIndexes.Add( CurPos );

				CurPos++;
			}

			// Modifying and adding other elements
			for( unsigned j = i; j < tMerged.Count(); j++ )
			{
				dgt_BoolElement_Ptr tEl = tMerged.Item( j );
				wxArrayInt t_op = tEl->get_OpCodes();
				wxArrayInt res_op;

				for( unsigned k = 0; k < t_op.Count(); k++ )
				{
					int item = t_op.Item( k );
					if( t_op.Item( k ) > 0 )
						res_op.Add( item );
					else
					{
						res_op.Add( -StartPos - ( k + 1 ) );
					}
				}

				tEl->set_OpCodes( res_op );

				if( j == ( tMerged.Count() - 1 ) )
					AndIndexes.Add( CurPos );

				resArray.Add( tEl );
				CurPos++;
			}
		}
	}

	// Correcting OR
	dgt_BoolElement_Ptr genOr( new dgt_BoolElement() );
	for( unsigned i = 0; i < AndIndexes.Count(); i++ )
	{
		genOr->AddNewOperand( -(AndIndexes.Item( i )), true );
	}
	
	int tCount = genOr->Count();
	if( tCount < inOrInputs )
	{
		dgt_BoolElement_Ptr tEl = genOr->IncreaseInputs( inOrInputs );
		resArray.Add( tEl );
		CurPos++;
	}
	if( tCount > inOrInputs )
	{
		BoolElementArray tAr = genOr->ReduceInputs( inOrInputs );
		BoolElementArray tMerged = MergeElements( tAr, inOrInputs, false );
		for( unsigned i = 0; i < tMerged.Count(); i++ )
			resArray.Add( tMerged.Item( i ) );
	}

	RETURN( "dgt_BoolConverter::get_MainForm", result );
	return result;
}

/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_NOTAND( short inNotAndInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_NOTAND" );
	LOG_PARAM( inNotAndInputs );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_NOTAND", result );
	return result;
}	

/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_ORNOTAND( short inOrInputs, short inNotAndInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_ORNOTAND" );
	LOG_PARAM( inOrInputs );
	LOG_PARAM( inNotAndInputs );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_ORNOTAND", result );
	return result;
}

/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_NOTOROR( short	inNotOrInputs, short inOrInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_NOTOROR" );
	LOG_PARAM( inNotOrInputs );
	LOG_PARAM( inOrInputs );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_NOTOROR", result );
	return result;
}


/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_ANDNOTOR( short inAndInputs, short	inNotOrInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_ANDNOTOR" );
	LOG_PARAM( inAndInputs );
	LOG_PARAM( inNotOrInputs );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_ANDNOTOR", result );
	return result;
}


/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_NOTANDAND(	short inNotAndInputs, short inAndInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_NOTANDAND" );
	LOG_PARAM( inNotAndInputs );
	LOG_PARAM( inAndInputs );
	
	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_NOTANDAND", result );
	return result;
}


/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_ORAND(	short inOrInputs,short inAndInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_ORAND" );
	LOG_PARAM( inOrInputs );
	LOG_PARAM( inAndInputs );

	dgt_BoolFunction_Ptr result;
	
	RETURN( "dgt_BoolConverter::get_Form_ORAND", result );
	return result;
}


/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::get_Form_NOTOR(	short inNotOrInputs )
{
	START( "DgtKernel", "dgt_BoolConverter::get_Form_NOTOR" );
	LOG_PARAM( inNotOrInputs );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::get_Form_NOTOR", result );
	return result;
}


/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::Minimize( void )
{
	START( "DgtKernel", "dgt_BoolConverter::Minimize" );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::Minimize", result );
	return result;
}

/**********************************************************************************************/
dgt_BoolFunction_Ptr dgt_BoolConverter::Factorize( void )
{
	START( "DgtKernel", "dgt_BoolConverter::Factorize" );

	dgt_BoolFunction_Ptr result;

	RETURN( "dgt_BoolConverter::Factorize", result );
	return result;
}